package data

import (
	"context"
	"errors"
	"github.com/bytedance/sonic"
	"github.com/go-kratos/kratos/contrib/registry/nacos/v2"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport/grpc"
	"github.com/redis/go-redis/v9"
	"hello-kratos/kratos-client/internal/biz"
	v1 "hello-kratos/kratos-server/api/v1"
	"time"
)

type userRepo struct {
	data *Data
	rpc  v1.UserClient
	l    *log.Helper
}

func (repo *userRepo) Login(ctx context.Context, ul *biz.UserLogin) error {
	u, err := repo.rpc.FindUserForLogin(ctx, &v1.FindUserForLoginRequest{
		Username: ul.UserName,
		Password: ul.PassWord,
	})
	if err != nil {
		return err
	}
	user := &biz.User{
		Id:       u.GetId(),
		Account:  u.GetAccount(),
		NickName: u.GetNickname(),
		Age:      u.GetAge(),
		Gender:   u.GetGender(),
		Remark:   u.GetRemark(),
	}
	// 缓存用户信息
	return repo.data.redis.client.SetEx(ctx, "kratos:user:"+user.Account, user, time.Hour*2).Err()
}

func (repo *userRepo) GetUserInfo(ctx context.Context, id string) (*biz.UserLogin, error) {
	cmd := repo.data.redis.client.Get(ctx, id)
	if cmd.Err() == redis.Nil {
		return nil, errors.New("user have not login, or login timeout")
	}
	ul := new(biz.UserLogin)
	if err := sonic.Unmarshal([]byte(cmd.Val()), ul); err != nil {
		return nil, err
	}
	return ul, nil
}

func NewUserRepo(data *Data, logger log.Logger, r *nacos.Registry) (biz.UserRepo, func(), error) {
	conn, err := grpc.DialInsecure(
		context.Background(),
		grpc.WithEndpoint("discovery:///kratos-server.grpc"),
		grpc.WithDiscovery(r),
	)
	if err != nil {
		return nil, nil, err
	}
	l := log.NewHelper(logger)
	return &userRepo{
			data: data,
			l:    l,
			rpc:  v1.NewUserClient(conn),
		}, func() {
			if err = conn.Close(); err != nil {
				l.Errorf("close grpc user client error: %s", err.Error())
			}
		}, nil
}
